<template>

  <basic-container>
    <el-page-header @back="onBack">
      <template #content>
        <div class="flex items-center">
          <el-icon>
            <Connection/>
          </el-icon>
          <el-text size="large" tag="b"> 品类草稿=></el-text>
          <el-text size="large"> {{ detail.categoryName }}</el-text>
        </div>
      </template>
      <template #extra>
        <div class="flex items-center">
          <el-button v-if="!this.snapshotMode" type="primary" icon="el-icon-success-filled" @click="publishOnline">
            发布上线
          </el-button>
        </div>
      </template>

      <basic-container>
        <el-descriptions :column="1" size="small">
          <el-descriptions-item label="品类名称 :">
            {{ detail.categoryNameFull }}
          </el-descriptions-item>
          <el-descriptions-item label="发布状态 :">
            {{ detail.status === 1 ? '已发布' : '未发布' }}
          </el-descriptions-item>
          <el-descriptions-item label="品类说明 :">
            {{ detail.categoryDesc }}
          </el-descriptions-item>
        </el-descriptions>
      </basic-container>

      <el-row>
        <el-alert type="info" show-icon>
          <template #title>
            <el-text size="small">您正在编辑的是草稿，需点击 </el-text>
            <el-text size="small" type="primary" class="cursor" @click="publishOnline">发布上线</el-text>
            <el-text size="small"> 后，物模型才会正式生效。</el-text>
          </template>
        </el-alert>
      </el-row>
      <el-row>
        <el-tooltip
          class="item"
          effect="dark"
          content="快速查找现有品类的物模型配置，并导入覆盖至当前品类的物模型草稿数据"
          placement="top"
        >
          <el-button @click="openImport">快速导入</el-button>
        </el-tooltip>
        <el-tooltip
          class="item"
          effect="dark"
          content="查看物模型的 TSL(Thing Specification Language) 描述语言"
          placement="top"
        >
          <el-button @click="openTsl">物模型 TSL</el-button>
        </el-tooltip>
        <el-tooltip
          class="item"
          effect="dark"
          content="将JSON格式的物模型配置文件读取，并导入覆盖至当前品类的物模型草稿数据"
          placement="top"
        >
          <el-button @click="importTsl">物模型 导入</el-button>
        </el-tooltip>
        <el-select style="width:260px" v-model="versionId"
                   filterable
                   placeholder="历史版本"
                   @change="versionChange"
                   class="margin-node">
          <el-option
              v-for="item in versionSelect"
              :key="item.id"
              :label="`${item.versionName}`"
              :value="item.id">
            <span style="float: left">{{ item.versionName }}</span>
            <span style="float: right;color: #8492a6;font-size: 13px;">
              {{ item.versionTime }}
            </span>
          </el-option>
        </el-select>
        <el-button v-if="this.versionId > 0" class="margin-node" @click="versionRecovery">恢复此版本</el-button>
        <el-button v-if="this.versionId > 0" class="margin-node" @click="versionReset">返回原版本</el-button>
      </el-row>
      <el-row>
        <avue-crud ref="crud"
                   :option="option"
                   :data="data"
                   v-model="form"
                   :table-loading="loading"
                   :before-open="beforeOpen"
                   :before-close="beforeClose"
                   @row-save="rowSave"
                   @row-update="rowUpdate"
                   @row-del="rowDel"
                   @on-load="onLoad">
          <template #menu-left>
            <el-button v-if="!this.snapshotMode" type="primary"
                       icon="el-icon-circle-plus"
                       @click="$refs.crud.rowAdd()">添加功能
            </el-button>
          </template>
          <template #functionType="{ row }">
            <el-tag style="cursor: pointer">{{ row.functionTypeName }}</el-tag>
          </template>
          <template #specEnum-form="{}">
            <function-enum v-model="enumsData" :snapshot-mode="snapshotMode"></function-enum>
          </template>
          <template #specStruct-form="{}">
            <function-struct v-model="structData" :snapshot-mode="snapshotMode"></function-struct>
          </template>
          <template #specInput-form="{}">
            <function-struct-full v-model="inputData" :snapshot-mode="snapshotMode"></function-struct-full>
          </template>
          <template #specOutput-form="{}">
            <function-struct-full v-model="outputData" :snapshot-mode="snapshotMode"></function-struct-full>
          </template>
        </avue-crud>
        <el-dialog v-model="visibleImport" :before-close="beforeCloseImport" title="物模型快速导入" width="500">
          <el-row>
            <el-alert title="导入物模型将覆盖现有草稿数据" type="warning" show-icon :closable="false"/>
          </el-row>
          <el-row>
            <avue-form ref="formImport"
                       :option="optionImport"
                       v-model="formImport"
                       @submit="handleImport">
            </avue-form>
          </el-row>
        </el-dialog>
        <el-dialog v-model="visibleTsl" :before-close="beforeCloseTsl" title="物模型" width="600">
          <el-row>
            <el-alert
                title="物模型是云端对设备功能的抽象描述，涵盖了设备的属性、服务和事件。物联网平台通过物的描述语言，即 TSL（Thing Specification Language），以 JSON 格式表达这一模型。开发者可以利用 TSL 构建并上报设备数据。完整的物模型可用于云端应用的开发，而精简版的物模型则可结合设备端SDK用于设备的开发工作。"
                type="info" :closable="false"/>
          </el-row>
          <el-row>
            <code-editor v-model="tsl" :json="true" :readonly="true" theme="nord"/>
          </el-row>
        </el-dialog>
        <el-dialog v-model="visibleTslImport" :before-close="beforeCloseTslImport" title="物模型导入" width="600">
          <el-upload
            drag
            accept=".json"
            :show-file-list="false"
            :action="'/api/blade-iot/category/version/tsl-import?categoryId=' + this.categoryId"
            :headers="uploadHeaders"
            :on-success="uploadSuccess"
            :on-error="uploadError"
          >
            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
            <div class="el-upload__text">
              拖动文件上传 <em>或者点击上传</em>
            </div>
            <template #tip>
              <div class="el-upload__tip">
                请上传JSON格式的物模型文件
              </div>
            </template>
          </el-upload>
        </el-dialog>
      </el-row>
    </el-page-header>
  </basic-container>
</template>

<script>
import {getDetail} from "@/api/iot/category";
import {select as selectVersion, dataSnapshot, dataRecovery, dataImport, dataDraftedTsl} from "@/api/iot/category/version";

import {mapGetters} from "vuex";
import {dataTypeName, fieldTypeName, option, optionCategoryImport} from '@/option/iot/function'
import {
  getList as functionList,
  getDetail as functionDetail,
  add as functionAdd,
  update as functionUpdate,
  remove as functionRemove,
  publishOnline
} from "@/api/iot/category/function";
import {validatenull} from "@/utils/validate";
import func from "@/utils/func";
import { getToken } from '@/utils/auth';

export default {
  name: "categoryDraft",
  data() {
    return {
      activeName: 'info',
      categoryId: '',
      categoryKey: '',
      versionId: '',
      form: {},
      formImport: {},
      tsl: {},
      detail: {},
      query: {},
      search: {},
      loading: false,
      visible: false,
      visibleImport: false,
      visibleTsl: false,
      visibleTslImport: false,
      versionSelect: [],
      snapshotMode: false,
      option: option(this),
      optionImport: optionCategoryImport,
      data: [],
      structData: [],
      enumsData: [],
      inputData: [],
      outputData: [],
      dataSnapshot: {},
      functionSnapshot: [],
      uploadHeaders: {
        'Blade-Auth': `bearer ${getToken()}`,
        'Blade-Requested-With': 'BladeHttpRequest'
      },
    };
  },
  computed: {
    ...mapGetters(["permission"]),
  },
  watch: {
    snapshotMode() {
      if (this.snapshotMode) {
        this.snapshotOperation();
      } else {
        this.editOperation();
      }
    },
  },
  mounted() {
    this.editOperation();
  },
  created() {
    this.init();
  },
  methods: {
    init() {
      this.categoryId = this.$route.params.categoryId;
      this.versionId = "";
      getDetail(this.categoryId).then(res => {
        this.detail = res.data.data;
      });
      selectVersion(this.categoryId).then(res => {
        this.versionSelect = res.data.data;
      });
    },
    onBack() {
      const key = this.categoryId;
      this.$router.push({
        path: `/iot/category/detail/${key}`,
        query: {
          activeKey: 'function'
        }
      });
      this.$router.$avueRouter.closeTag();
    },
    snapshotOperation() {
      this.$refs.crud.option.editBtn = false;
      this.$refs.crud.option.delBtn = false;
      this.$refs.crud.option.viewBtn = true;
    },
    editOperation() {
      this.$refs.crud.option.editBtn = true;
      this.$refs.crud.option.delBtn = true;
      this.$refs.crud.option.viewBtn = false;
    },
    openImport() {
      this.visibleImport = true;
    },
    beforeCloseImport() {
      this.$refs.formImport.resetForm();
      this.visibleImport = false;
    },
    handleImport(form, done, loading) {
      this.$confirm('即将覆盖现有数据无法找回，是否导入此版本?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        dataImport(form.versionId, this.categoryId).then(() => {
          this.$message({
            type: "success",
            message: "导入成功!"
          });
          this.beforeCloseImport();
          this.onLoad();
          done();
        }, error => {
          loading();
          window.console.log(error);
        });
      }).catch(() => {
        done();
      });
    },
    uploadSuccess(response) {
      console.log(response);
      this.$confirm('物模型数据导入完毕，是否刷新数据?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.onLoad();
        this.beforeCloseTslImport();
      })
    },
    uploadError(error) {
      console.log(error.message);
      this.$message.error("导入失败请检查文件格式！");
    },
    versionChange(value) {
      this.versionId = value;
      dataSnapshot(value).then(res => {
        this.dataSnapshot = res.data.data;
        // 将三个列表合并返回
        const properties = this.dataSnapshot.properties;
        const commands = this.dataSnapshot.commands;
        const events = this.dataSnapshot.events;
        // 设置功能列表快照
        this.functionSnapshot = [...properties, ...commands, ...events];
        this.data = this.functionSnapshot;
        this.snapshotMode = true;
      });
    },
    versionRecovery() {
      this.$confirm('即将覆盖现有数据无法找回，是否恢复此版本?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        dataRecovery(this.versionId).then(() => {
          this.$message({
            type: "success",
            message: "操作成功!"
          });
          this.versionReset();
        });
      })
    },
    versionReset() {
      this.versionId = "";
      this.dataSnapshot = {};
      this.functionSnapshot = [];
      this.snapshotMode = false;
      this.init();
      this.onLoad();
    },
    transForm(row) {
      // 功能类型
      const functionType = this.form?.functionType;
      if (functionType === 2) {
        // 输入参数
        this.inputData = row.specInput;
        // 输出参数
        this.outputData = row.specOutput;
      }
      if (functionType === 3) {
        // 输出参数
        this.outputData = row.specOutput;
      }
      // 属性功能
      if (functionType === 1) {
        if (row.specFunction.fieldType === "enum") {
          // 枚举数据
          this.enumsData = func.keyValueToJsonArray(row.specFunction.specEnum);
        }
        if (row.specFunction.fieldType === "struct") {
          // 属性结构体
          this.structData = row.specFunction.specStruct;
        }
        row.specFunctionId = row.specFunction.id; // 功能主键
        row.fieldType = row.specFunction.fieldType; // 数据类型
        row.specMin = row.specFunction.specMin; // 最小值
        row.specMax = row.specFunction.specMax; // 最大值
        row.specStep = row.specFunction.specStep; // 步长
        row.specUnit = row.specFunction.specUnit; // 单位
        row.specEnum = row.specFunction.specEnum; // 枚举数据
        row.specBoolFalse = row.specFunction.specBoolFalse; // 布尔值 0
        row.specBoolTrue = row.specFunction.specBoolTrue; // 布尔值 1
        row.specLength = row.specFunction.specLength; // 数据长度
        row.specDateFormat = row.specFunction.specDateFormat; // 时间格式
        row.specItemType = row.specFunction.specItemType; // 元素类型
        row.specSize = row.specFunction.specSize; // 元素个数

      }
      return row;
    },
    buildForm(row) {
      // 功能类型
      const functionType = this.form?.functionType;
      // 产品id
      row.categoryId = this.categoryId;
      // 结构体参数默认为空
      row.specFunction = {};
      // 输入参数默认为空
      row.specInput = [];
      // 输出参数默认为空
      row.specOutput = [];
      if (functionType === 2) {
        // 输入参数
        row.specInput = this.inputData;
        // 输出参数
        row.specOutput = this.outputData;
      }
      if (functionType === 3) {
        // 输出参数
        row.specOutput = this.outputData;
      }
      // 属性功能
      if (functionType === 1) {
        if (row.fieldType === "enum") {
          // 枚举参数
          row.specEnum = func.jsonArrayToKeyValue(this.enumsData);
        }
        row.specFunction = {
          id: row.specFunctionId, // 功能主键
          functionType: row.functionType, // 功能类型
          name: row.name, // 功能名称
          identifier: row.identifier, // 标识符
          fieldType: row.fieldType, // 数据类型
          specMin: row.specMin, // 最小值
          specMax: row.specMax, // 最大值
          specStep: row.specStep, // 步长
          specUnit: row.specUnit, // 单位
          specEnum: row.specEnum, // 枚举数据
          specBoolFalse: row.specBoolFalse, // 布尔值 0
          specBoolTrue: row.specBoolTrue, // 布尔值 1
          specLength: row.specLength, // 数据长度
          specDateFormat: row.specDateFormat, // 时间格式
          specItemType: row.specItemType, // 元素类型
          specSize: row.specSize, // 元素个数
          specStruct: (
              row.fieldType === "struct" || row.specItemType === "struct"
          ) ? this.structData : [] // 结构体参数
        };
      }
      return row;
    },
    beforeOpen(done, type) {
      if (["edit"].includes(type)) {
        functionDetail(this.form.id, this.form.functionType).then(res => {
          const data = res.data.data;
          this.form = this.transForm(data);
          if (data.functionType === 1) {
            this.form.fieldType = data.specFunction.fieldType;
            this.form.specFunctionId = data.specFunction.id;
          }
        });
      }
      if (["view"].includes(type)) {
        const data = this.functionSnapshot.find(item => item.id === this.form.id);
        this.form = this.transForm(data);
        if (data.functionType === 1) {
          this.form.fieldType = data.specFunction.fieldType;
          this.form.specFunctionId = data.specFunction.id;
        }
      }
      done();
    },
    beforeClose(done) {
      this.form = {};
      this.structData = [];
      this.enumsData = [];
      this.inputData = [];
      this.outputData = [];
      done();
    },
    rowSave(row, done, loading) {
      functionAdd(this.buildForm(row)).then(() => {
        this.onLoad();
        this.$message({
          type: "success",
          message: "操作成功!"
        });
        done();
      }, error => {
        loading();
        window.console.log(error);
      });
    },
    rowUpdate(row, index, done, loading) {
      functionUpdate(this.buildForm(row)).then(() => {
        this.onLoad();
        this.$message({
          type: "success",
          message: "操作成功!"
        });
        done();
      }, error => {
        loading();
        console.log(error);
      });
    },
    rowDel(row) {
      this.$confirm("确定将选择数据删除?", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      }).then(() => {
        return functionRemove(row.id, row.functionType);
      }).then(() => {
        this.onLoad();
        this.$message({
          type: "success",
          message: "操作成功!"
        });
      });
    },
    openTsl() {
      dataDraftedTsl(this.categoryId).then(res => {
        this.tsl = JSON.stringify(res.data.data);
      });
      this.visibleTsl = true;
    },
    importTsl() {
      this.$confirm('即将覆盖现有数据无法找回，是否继续？', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => {
          this.visibleTslImport = true;
        })
    },
    beforeCloseTsl() {
      this.tsl = "";
      this.visibleTsl = false;
    },
    beforeCloseTslImport() {
      this.visibleTslImport = false;
    },
    onLoad(params = {}) {
      const categoryId = this.categoryId;
      if (validatenull(categoryId)) {
        return;
      }
      params = {
        ...params,
        categoryId,
      }
      this.loading = true;
      functionList(params).then(res => {
        this.data = res.data.data.map(item => {
          return {
            ...item,
            fieldTypeName: fieldTypeName(item),
            dataTypeName: dataTypeName(item)
          }
        });
        this.loading = false;
      });
    },
    publishOnline() {
      this.$prompt('发布备注', '发布物模型上线', {
        confirmButtonText: '发布',
        cancelButtonText: '关闭',
      }).then(({value}) => {
        publishOnline(this.categoryId, value).then(() => {
          this.$message({
            type: "success",
            message: "发布成功!"
          });
          this.onBack();
        });
      })
    },
  }
};
</script>

<style>
.cursor {
  cursor: pointer;
}

.margin-node {
  margin-left: 12px;
}
</style>
